from __future__ import annotations

import uuid
import json
from fastapi import Request, HTTPException
from app.entity.system import AuthData, SysUser
from config.app import get_config
from core.utils import en_password_md5
from core.storage import RedisStorage
from app.dao.system import SysUserDao


class AuthService:

    def __init__(self, req: Request):
        self.req = req

    async def login(self, auth: AuthData) -> (bool, str):
        # 验证码校验
        r = await self.validateCaptcha(auth.username, auth.code, auth.key)

        if not r[0]:
            return r

        # 登录前置校验
        user = await self.loginPreCheck(auth.username, auth.password)

        # 记录用户登录信息
        # 更新用户登录信息
        # 创建Token
        if user is None:
            return False, '用户名密码不正确'

        token:str = await self.create_token(user)
        if token is None:
            return False, '用户Token创建失败'
        return True,token

    async def validateCaptcha(self, username: str, code: str, uuid: str) -> (bool, str):

        config = get_config()

        if config.CAPTCHA_ENABLE:
            key = config.CAPTCHA_PREFIX + uuid
            res = await RedisStorage.get_cache_object(self.req.app, key)

            if res is None or res != code.lower():
                return False, '验证码不正确'

        return True, ''

    async def loginPreCheck(self, username: str, password: str) -> SysUser | None:
        # todo: 验证IP黑名单

        userDao = await SysUserDao.instance(self.req)
        user = await userDao.select_by_name(username)
        if user is None:
            return None
        print(en_password_md5(password, user.salt) , user.password)
        if en_password_md5(password, user.salt) != user.password:
            return None

        return user

    async def create_token(self, user: SysUser) -> str | None:
        config = get_config()
        token = str(uuid.uuid4())
        key = config.TOKEN_PREFIX + en_password_md5(token, config.TOKEN_SECRET)
        try:
            await RedisStorage.set_cache_object(self.req.app, key, json.dumps(user.dict()), config.TOKEN_EXPIRE)
            return token
        except Exception as e:
            return None

    @classmethod
    async def instance(cls, req: Request):
        inst = cls(req)
        return inst
